﻿using System;

namespace Hxsoft.AppV1
{
	public struct LoadedValue<T>
	{
		private bool _isLoaded;
		private bool _isSetted;
		private T _value;
		private LoadValue<T> _loader;
		private SetValue<T> _setter;

		public bool IsLoaded { get { return _isLoaded; } }
		public bool IsSetted { get { return _isSetted; } }

		public T Value
		{
			get
			{
				if (!IsLoaded && _loader != null)
				{
					_value = _loader();
					_isLoaded = true;
				}

				if (!IsLoaded)
					throw new InvalidOperationException(Res.LoadedValue_NotLoadedValue);

				return _value;
			}
			set
			{
				if (_setter != null)
					_setter(value);
				_value = value;
				_isLoaded = true;
				_isSetted = true;
			}
		}

		public LoadValue<T> Loader
		{
			get { return _loader; }
			set { _loader = value; }
		}

		public SetValue<T> Setter
		{
			get { return _setter; }
			set { _setter = value; }
		}



		public void ResetValue()
		{
			_isLoaded = false;
			_value = default(T);
			_isSetted = false;
		}



		#region LoadedValue
		public LoadedValue(T value) : this(value, null, null)
		{
		}

		public LoadedValue(T value, LoadValue<T> loader, SetValue<T> setter)
		{
			_value = value;
			_isLoaded = true;
			_isSetted = true;
			_loader = loader;
			_setter = setter;
		}

		public LoadedValue(LoadValue<T> loader, SetValue<T> setter)
		{
			_value = default(T);
			_isLoaded = false;
			_isSetted = false;
			_loader = loader;
			_setter = setter;
		}
		#endregion



		#region GetValueOrDefault
		public T GetValueOrDefault()
		{
			return _value;
		}

		public T GetValueOrDefault(T defaultValue)
		{
			if (!IsLoaded)
			{
				return defaultValue;
			}

			return _value;
		}
		#endregion



		#region override
		public override bool Equals(object other)
		{
			if (!IsLoaded)
			{
				return (other == null);
			}
			if (other == null)
			{
				return false;
			}
			return _value.Equals(other);
		}

		public override int GetHashCode()
		{
			if (!IsLoaded)
			{
				return 0;
			}
			return _value.GetHashCode();
		}

		public override string ToString()
		{
			if (!IsLoaded)
			{
				return "";
			}
			return _value.ToString();
		}
		#endregion



		#region operator
		public static implicit operator LoadedValue<T>(T value)
		{
			return new LoadedValue<T>(value);
		}

		public static explicit operator T(LoadedValue<T> value)
		{
			return value.Value;
		}
		#endregion
	}

	public delegate ValueType LoadValue<ValueType>();
	public delegate void SetValue<ValueType>(ValueType value);
}